/**
 * 
 */
package edu.umd.clip.lm.util.tree;

import java.util.*;
import edu.umd.clip.lm.util.*;
/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class GraphvizOutput {
	private String graphName;
	private StringBuffer output;
	private int lastNode = 0;
	private HashMap<Object, String> nodeNames;
	public GraphvizOutput(String name) {
		graphName = name;
	}

	private void prolog() {
		output = new StringBuffer();
		lastNode = 0;
		nodeNames = new HashMap<Object, String>();
		output.append("digraph " + graphName + " {\n");		
	}
	
	private void epilog() {
		output.append("}\n");
		nodeNames = null;		
	}
	
	public <T extends XMLizable> String getOutput(BinaryTree<T> tree) {
		prolog();
		BinaryTreeFinder<T> finder = new BinaryTreeFinder<T>() {
			/* (non-Javadoc)
			 * @see edu.umd.clip.lm.util.tree.BinaryTreeFinder#apply(edu.umd.clip.lm.util.tree.BinaryTree)
			 */
			public boolean apply(BinaryTree<T> node) {
				T payload = node.getPayload();
				String nodename = getName(node); 
				output.append("  " + nodename);
				output.append(" [label=\""+(payload==null?"<NULL>":getText(payload).replace("\"", "\\\"").replace("\n","\\n"))+"\"];\n");
				
				if (!node.isLeaf()) {
					String list = ""; 
					if (node.getLeft() != null) {
						list += " " + getName(node.getLeft());
					}
					if (node.getRight() != null) {
						list += " " + getName(node.getRight());
					}
					output.append("  " + nodename + " -> {" + list + " };\n");
					output.append("  {rank=same;" + list + "}\n");			
				}
				return false;
			}
		};
		tree.searchPreorder(finder);
		epilog();
		return output.toString();
	}
	
	public <T> String getOutput(AnyaryTree<T> tree) {
		prolog();
		AnyaryTreeFinder<T> finder = new AnyaryTreeFinder<T>() {
			/* (non-Javadoc)
			 * @see edu.umd.clip.lm.util.tree.AnyaryTreeFinder#apply(edu.umd.clip.lm.util.tree.AnyaryTree)
			 */
			public boolean apply(AnyaryTree<T> node) {
				T payload = node.getPayload();
				String nodename = getName(node); 
				output.append("  " + nodename);
				output.append(" [label=\""+(payload==null?"<NULL>":getText(payload).replace("\"", "\\\"").replace("\n","\\n"))+"\"];\n");
				
				if (!node.isLeaf()) {
					String list = "";
					for(AnyaryTree<T> child : node.getChildren()) {
						list += " " + getName(child);
						//output.append("  " + nodename + " -> " + getName(child) + ";\n");
					}
					output.append("  " + nodename + " -> {" + list + " };\n");
					output.append("  {rank=same;" + list + "}\n");
				}
				return false;
			}			
		};
		tree.searchPreorder(finder);
		epilog();
		return output.toString();
	}

	private String getName(Object node) {
		String name = nodeNames.get(node);
		if (name == null) {
			name = "N" + Integer.toString(lastNode++);
			nodeNames.put(node, name);
		}
		return name;
	}

	protected <T> String getText(T payload) {
		return payload.toString();
	}
}
